/**
 * 渲染错误处理器
 * 处理Canvas渲染失败、动画错误等渲染相关问题
 * 提供CSS降级方案确保游戏在渲染失败时仍能运行
 * @class
 */

export interface RenderFallbackOptions {
  /** 是否启用CSS降级渲染 */
  enableCSSFallback?: boolean
  /** CSS降级容器的ID */
  fallbackContainerId?: string
  /** 是否在降级时显示警告信息 */
  showFallbackWarning?: boolean
  /** 降级模式下的更新频率（毫秒） */
  fallbackUpdateInterval?: number
}

export interface RenderErrorInfo {
  /** 错误类型 */
  type: 'canvas' | 'context' | 'animation' | 'texture' | 'shader'
  /** 错误消息 */
  message: string
  /** 错误对象 */
  error: Error
  /** 发生错误的时间戳 */
  timestamp: number
  /** 错误发生的上下文信息 */
  context?: any
}

/**
 * 渲染错误处理器类
 */
export class RenderErrorHandler {
  private options: Required<RenderFallbackOptions>
  private isInFallbackMode: boolean = false
  private fallbackContainer: HTMLElement | null = null
  private fallbackElements: Map<string, HTMLElement> = new Map()
  private errorHistory: RenderErrorInfo[] = []
  private maxErrorHistory: number = 50
  private fallbackUpdateTimer: number | null = null
  private errorCallbacks: Array<(error: RenderErrorInfo) => void> = []

  /**
   * 创建渲染错误处理器
   * @param options - 配置选项
   */
  constructor(options: RenderFallbackOptions = {}) {
    this.options = {
      enableCSSFallback: options.enableCSSFallback ?? true,
      fallbackContainerId: options.fallbackContainerId ?? 'game-fallback-container',
      showFallbackWarning: options.showFallbackWarning ?? true,
      fallbackUpdateInterval: options.fallbackUpdateInterval ?? 16
    }
  }

  /**
   * 处理Canvas相关错误
   * @param error - 错误对象
   * @param canvas - 出错的Canvas元素
   * @returns 是否成功处理错误
   */
  handleCanvasError(error: Error, canvas?: HTMLCanvasElement): boolean {
    const errorInfo: RenderErrorInfo = {
      type: 'canvas',
      message: `Canvas渲染错误: ${error.message}`,
      error,
      timestamp: Date.now(),
      context: { canvas: canvas?.id }
    }

    this.logError(errorInfo)

    // 尝试重新获取渲染上下文
    if (canvas) {
      try {
        const newContext = canvas.getContext('2d')
        if (newContext) {
          console.log('成功重新获取Canvas渲染上下文')
          return true
        }
      } catch (retryError) {
        console.error('重新获取Canvas上下文失败:', retryError)
      }
    }

    // 如果无法修复Canvas，启用CSS降级
    if (this.options.enableCSSFallback) {
      return this.fallbackToCSSRendering()
    }

    return false
  }

  /**
   * 处理渲染上下文错误
   * @param error - 错误对象
   * @param context - 出错的渲染上下文
   * @returns 是否成功处理错误
   */
  handleContextError(error: Error, context?: CanvasRenderingContext2D): boolean {
    const errorInfo: RenderErrorInfo = {
      type: 'context',
      message: `渲染上下文错误: ${error.message}`,
      error,
      timestamp: Date.now(),
      context: { contextType: '2d' }
    }

    this.logError(errorInfo)

    // 尝试重置渲染状态
    if (context) {
      try {
        context.save()
        context.restore()
        context.clearRect(0, 0, context.canvas.width, context.canvas.height)
        console.log('成功重置渲染上下文状态')
        return true
      } catch (resetError) {
        console.error('重置渲染上下文失败:', resetError)
      }
    }

    // 启用CSS降级
    if (this.options.enableCSSFallback) {
      return this.fallbackToCSSRendering()
    }

    return false
  }

  /**
   * 处理动画错误
   * @param error - 错误对象
   * @param animationName - 出错的动画名称
   * @returns 是否成功处理错误
   */
  handleAnimationError(error: Error, animationName?: string): boolean {
    const errorInfo: RenderErrorInfo = {
      type: 'animation',
      message: `动画错误: ${error.message}`,
      error,
      timestamp: Date.now(),
      context: { animationName }
    }

    this.logError(errorInfo)

    // 禁用有问题的动画
    if (animationName) {
      this.disableProblematicAnimation(animationName)
    }

    // 如果动画错误过多，考虑降级到静态渲染
    const recentAnimationErrors = this.errorHistory
      .filter(e => e.type === 'animation' && Date.now() - e.timestamp < 5000)
      .length

    if (recentAnimationErrors > 5 && this.options.enableCSSFallback) {
      console.warn('动画错误过多，启用CSS降级渲染')
      return this.fallbackToCSSRendering()
    }

    return true
  }

  /**
   * 处理纹理加载错误
   * @param error - 错误对象
   * @param textureUrl - 出错的纹理URL
   * @returns 是否成功处理错误
   */
  handleTextureError(error: Error, textureUrl?: string): boolean {
    const errorInfo: RenderErrorInfo = {
      type: 'texture',
      message: `纹理加载错误: ${error.message}`,
      error,
      timestamp: Date.now(),
      context: { textureUrl }
    }

    this.logError(errorInfo)

    // 使用默认纹理或颜色填充
    console.log(`使用默认纹理替代: ${textureUrl}`)
    return true
  }

  /**
   * 降级到CSS渲染模式
   * @returns 是否成功启用CSS降级
   */
  private fallbackToCSSRendering(): boolean {
    if (this.isInFallbackMode) {
      return true
    }

    try {
      // 创建或获取降级容器
      this.fallbackContainer = document.getElementById(this.options.fallbackContainerId)
      
      if (!this.fallbackContainer) {
        this.fallbackContainer = document.createElement('div')
        this.fallbackContainer.id = this.options.fallbackContainerId
        this.fallbackContainer.className = 'game-css-fallback'
        
        // 添加基础样式
        this.fallbackContainer.style.cssText = `
          position: relative;
          width: 800px;
          height: 400px;
          background: linear-gradient(to bottom, #87CEEB, #98FB98);
          overflow: hidden;
          border: 2px solid #333;
        `
        
        // 将降级容器插入到游戏容器中
        const gameContainer = document.querySelector('.game-container') || document.body
        gameContainer.appendChild(this.fallbackContainer)
      }

      // 显示降级警告
      if (this.options.showFallbackWarning) {
        this.showFallbackWarning()
      }

      // 启动CSS降级渲染循环
      this.startFallbackRendering()

      this.isInFallbackMode = true
      console.log('已启用CSS降级渲染模式')
      return true
    } catch (fallbackError) {
      console.error('启用CSS降级失败:', fallbackError)
      return false
    }
  }

  /**
   * 显示降级模式警告
   */
  private showFallbackWarning(): void {
    const warning = document.createElement('div')
    warning.className = 'fallback-warning'
    warning.style.cssText = `
      position: absolute;
      top: 10px;
      left: 10px;
      background: rgba(255, 165, 0, 0.9);
      color: white;
      padding: 8px 12px;
      border-radius: 4px;
      font-size: 12px;
      z-index: 1000;
      animation: fadeInOut 3s ease-in-out;
    `
    warning.textContent = '渲染降级模式已启用'

    // 添加CSS动画
    const style = document.createElement('style')
    style.textContent = `
      @keyframes fadeInOut {
        0%, 100% { opacity: 0; }
        50% { opacity: 1; }
      }
    `
    document.head.appendChild(style)

    this.fallbackContainer?.appendChild(warning)

    // 3秒后移除警告
    setTimeout(() => {
      warning.remove()
      style.remove()
    }, 3000)
  }

  /**
   * 启动CSS降级渲染循环
   */
  private startFallbackRendering(): void {
    if (this.fallbackUpdateTimer) {
      clearInterval(this.fallbackUpdateTimer)
    }

    this.fallbackUpdateTimer = window.setInterval(() => {
      this.updateFallbackRendering()
    }, this.options.fallbackUpdateInterval)
  }

  /**
   * 更新CSS降级渲染
   */
  private updateFallbackRendering(): void {
    if (!this.fallbackContainer) return

    // 这里可以更新CSS元素的位置和状态
    // 例如移动玩家元素、障碍物等
    this.updateFallbackElements()
  }

  /**
   * 更新降级模式下的游戏元素
   */
  private updateFallbackElements(): void {
    // 更新玩家元素
    this.updateFallbackPlayer()
    
    // 更新障碍物
    this.updateFallbackObstacles()
    
    // 更新背景
    this.updateFallbackBackground()
  }

  /**
   * 更新降级模式下的玩家元素
   */
  private updateFallbackPlayer(): void {
    let playerElement = this.fallbackElements.get('player')
    
    if (!playerElement) {
      playerElement = document.createElement('div')
      playerElement.className = 'fallback-player'
      playerElement.style.cssText = `
        position: absolute;
        width: 40px;
        height: 60px;
        background: #FF6B6B;
        border-radius: 8px;
        left: 100px;
        bottom: 50px;
        transition: all 0.1s ease;
      `
      
      this.fallbackContainer?.appendChild(playerElement)
      this.fallbackElements.set('player', playerElement)
    }

    // 简单的跳跃动画
    const jumpOffset = Math.sin(Date.now() * 0.01) * 20
    playerElement.style.transform = `translateY(${jumpOffset}px)`
  }

  /**
   * 更新降级模式下的障碍物
   */
  private updateFallbackObstacles(): void {
    // 创建简单的移动障碍物
    const obstacleCount = 3
    
    for (let i = 0; i < obstacleCount; i++) {
      const obstacleKey = `obstacle_${i}`
      let obstacle = this.fallbackElements.get(obstacleKey)
      
      if (!obstacle) {
        obstacle = document.createElement('div')
        obstacle.className = 'fallback-obstacle'
        obstacle.style.cssText = `
          position: absolute;
          width: 30px;
          height: 80px;
          background: #8B4513;
          border-radius: 4px;
          bottom: 50px;
        `
        
        this.fallbackContainer?.appendChild(obstacle)
        this.fallbackElements.set(obstacleKey, obstacle)
      }

      // 移动障碍物
      const baseX = 300 + i * 200
      const moveOffset = (Date.now() * 0.1) % 1000
      const currentX = baseX + moveOffset
      
      obstacle.style.left = `${currentX}px`
      
      // 如果障碍物移出屏幕，重置位置
      if (currentX > 850) {
        obstacle.style.left = `${baseX - 1000}px`
      }
    }
  }

  /**
   * 更新降级模式下的背景
   */
  private updateFallbackBackground(): void {
    if (!this.fallbackContainer) return

    // 简单的背景滚动效果
    const scrollOffset = (Date.now() * 0.05) % 100
    this.fallbackContainer.style.backgroundPosition = `${-scrollOffset}px 0`
  }

  /**
   * 禁用有问题的动画
   * @param animationName - 要禁用的动画名称
   */
  private disableProblematicAnimation(animationName: string): void {
    console.warn(`禁用有问题的动画: ${animationName}`)
    
    // 这里可以实现具体的动画禁用逻辑
    // 例如从动画管理器中移除该动画
    const style = document.createElement('style')
    style.textContent = `
      .animation-${animationName} {
        animation: none !important;
        transition: none !important;
      }
    `
    document.head.appendChild(style)
  }

  /**
   * 记录错误信息
   * @param errorInfo - 错误信息
   */
  private logError(errorInfo: RenderErrorInfo): void {
    this.errorHistory.push(errorInfo)
    
    // 限制错误历史记录数量
    if (this.errorHistory.length > this.maxErrorHistory) {
      this.errorHistory.shift()
    }

    // 触发错误回调
    this.errorCallbacks.forEach(callback => {
      try {
        callback(errorInfo)
      } catch (callbackError) {
        console.error('错误回调执行失败:', callbackError)
      }
    })

    console.error(`[RenderErrorHandler] ${errorInfo.message}`, errorInfo.error)
  }

  /**
   * 添加错误回调函数
   * @param callback - 错误回调函数
   */
  addErrorCallback(callback: (error: RenderErrorInfo) => void): void {
    this.errorCallbacks.push(callback)
  }

  /**
   * 移除错误回调函数
   * @param callback - 要移除的回调函数
   */
  removeErrorCallback(callback: (error: RenderErrorInfo) => void): void {
    const index = this.errorCallbacks.indexOf(callback)
    if (index > -1) {
      this.errorCallbacks.splice(index, 1)
    }
  }

  /**
   * 检查是否处于降级模式
   * @returns 是否处于CSS降级模式
   */
  isInFallback(): boolean {
    return this.isInFallbackMode
  }

  /**
   * 获取错误历史记录
   * @returns 错误历史记录数组
   */
  getErrorHistory(): RenderErrorInfo[] {
    return [...this.errorHistory]
  }

  /**
   * 获取错误统计信息
   * @returns 错误统计对象
   */
  getErrorStats(): {
    totalErrors: number
    errorsByType: Record<string, number>
    recentErrors: number
    isInFallbackMode: boolean
  } {
    const errorsByType: Record<string, number> = {}
    const recentThreshold = Date.now() - 60000 // 最近1分钟

    let recentErrors = 0

    this.errorHistory.forEach(error => {
      errorsByType[error.type] = (errorsByType[error.type] || 0) + 1
      if (error.timestamp > recentThreshold) {
        recentErrors++
      }
    })

    return {
      totalErrors: this.errorHistory.length,
      errorsByType,
      recentErrors,
      isInFallbackMode: this.isInFallbackMode
    }
  }

  /**
   * 清除错误历史记录
   */
  clearErrorHistory(): void {
    this.errorHistory = []
  }

  /**
   * 退出降级模式（如果可能）
   * @returns 是否成功退出降级模式
   */
  exitFallbackMode(): boolean {
    if (!this.isInFallbackMode) {
      return true
    }

    try {
      // 停止降级渲染循环
      if (this.fallbackUpdateTimer) {
        clearInterval(this.fallbackUpdateTimer)
        this.fallbackUpdateTimer = null
      }

      // 清理降级元素
      this.fallbackElements.clear()
      
      // 移除降级容器
      if (this.fallbackContainer) {
        this.fallbackContainer.remove()
        this.fallbackContainer = null
      }

      this.isInFallbackMode = false
      console.log('已退出CSS降级模式')
      return true
    } catch (error) {
      console.error('退出降级模式失败:', error)
      return false
    }
  }

  /**
   * 销毁错误处理器
   */
  destroy(): void {
    this.exitFallbackMode()
    this.errorCallbacks = []
    this.clearErrorHistory()
  }
}

/**
 * 全局渲染错误处理器实例
 */
export const renderErrorHandler = new RenderErrorHandler()